package generator.datastructure.j2xml_impl;

import generator.datastructure.ForkPoint;
import generator.datastructure.MethodDeclaration;
import generator.util.J2XMLManipulator;

import java.util.ArrayList;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**{@inheritDoc}
 * La clase extiende la funcionalidad de {@link ForkPoint} y representa la sentencia de bifurcación o
 * fork empleando la biblioteca javaToXml*/
public class ForkPointJ2XML extends ForkPoint {
	
	/**{@link org.w3c.dom.Element} (perteneciente al árbol DOM utilizado para representar una clase java)
	 * que representa a punto de fork y cuyo formato responde al impuesto por la biblioteca JavaToXml*/
	protected Element forkElement;
	
	/**Objeto que se utilizará para realizar operaciones genéricas sobre la sentencia fork
	 * representadas como elementos que responden al formato impuesto por la biblioteca
	 * JavaToXml*/
	protected J2XMLManipulator jm;
	
	/**Objeto utilizado para evaluar expresiones xpath sobre archivos xml*/
	protected XPath xpath;
	
	/**Contructor que retorna un objeto de la clase con todos sus atributos seteados
	 * @param forkElement
	 * 			sentencia fork representada mediante un {@link org.w3c.dom.Element} que responde al
	 * 			formato	impuesto por la biblioteca javaToXml
	 * @param md
	 * 			objeto que representa la declaración del método donde se encuentra contenido
	 * 			el punto de bifurcación.*/
	public ForkPointJ2XML(Element forkElement, MethodDeclaration md){
		super();
		jm = new J2XMLManipulator();
		xpath = XPathFactory.newInstance().newXPath();
		this.forkElement = forkElement;
		super.setMethodOwner(md);
		super.setRealParams(this.extractRealParams());		
		super.setGridVariableName(jm.getVarNameInAssignment(this.forkElement));		
	}
	
	/**Constructor mediante el cual se obtiene un objeto de la clase con ninguno de sus atributos 
	 * seteados*/
	public ForkPointJ2XML(){
		
	}

	/**@return sentencia fork representada mediante un {@link org.w3c.dom.Element} que responde al
	 * 			 formato impuesto por la biblioteca javaToXml*/
	public Element getForkElement() {
		return forkElement;
	}

	/**@param forkElement
	 * 			sentencia fork representada mediante un {@link org.w3c.dom.Element} que responde al
	 * 			formato	impuesto por la biblioteca javaToXml*/
	public void setForkElement(Element forkElement) {
		this.forkElement = forkElement;
	}

	/**{@inheritDoc}*/
	@Override	
	public boolean hasDeclaration() {		
		return forkElement.getTagName().compareTo(jm.LOCALVARIABLE)==0;
		
	}
	
	/**Este método obtiene los nombres de los parámetros reales de una sentencia fork. <BR>
	 * NOTA: NO admite expresiones o llamados a métodos como parámetros reales, sólo variables o constantes.
	 * @return lista con los nombres de cada parámetro real de la sentencia fork, ordenados según su posición
	 * 			en la invocación.
	 * */
	protected ArrayList<String> extractRealParams(){		
		
		ArrayList<String> realParams = new ArrayList<String>();		
		try {
			//obtengo todos los argumentos que se pasan en el llamado o fork
			NodeList listArgs = this.getInvocationParams();
			
			//a los nodos que representan los argumentos reales les extraigo su nombre  
			for (int i = 0; i<listArgs.getLength(); i++){								
				Element arg = (Element)listArgs.item(i);									
				if (arg.getNodeName().compareTo(jm.VARREF)==0)
					realParams.add(realParams.size(),arg.getAttribute("name"));
				else
					if (arg.getNodeName().compareTo(jm.THIS)==0)
						realParams.add(realParams.size(), arg.getNodeName());
					else//significa que es un literal (int, char, long, float, etc)
						realParams.add(realParams.size(),arg.getAttribute("value"));						
			}
			return realParams;
		
		} catch (Exception e) {
			System.err.println("Error al reconocer argumentos reales del Fork");
			return realParams;
		}		
	}
	
	/**Obtiene elementos de tipo {@link org.w3c.dom.Element} que representan los parámetros reales de
	 * una sentencia fork. <BR> Estos elementos responden al formato impuesto por la biblioteca javaToXml 
	 * @return retorna una {@link org.w3c.dom.NodeList} en donde los elemento recorridos en orden, 
	 * representan los parámetros reales de la sentencia fork.*/
	protected NodeList getInvocationParams(){
		try {
			return (NodeList)xpath.evaluate("self::*//send[@message ='"+this.getMethodOwner().getMethodName()+"']/arguments/*", this.forkElement,XPathConstants.NODESET);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
			return null;
		}
	}	

}
